package org.jthompson.monsoon.spring;

import org.apache.log4j.Logger;
import org.jthompson.monsoon.EventMapping;
import org.jthompson.monsoon.annotations.Event;
import org.jthompson.monsoon.annotations.Event.EventType;
import org.jthompson.monsoon.factory.CGLibObjectFactory;
import org.jthompson.monsoon.factory.ObjectFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class EventBeanPostProcessor implements BeanFactoryPostProcessor, BeanPostProcessor
{

	private ObjectFactory factory;

	public EventBeanPostProcessor()
	{
		 factory = CGLibObjectFactory.instance();
	}
	
	private List<String> managedBeanNames = new ArrayList<String>();

	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException
	{
		for(String name : managedBeanNames)
		{
			if(beanName.equals(name))
			{
				for(Method m : bean.getClass().getMethods())
				{
					if(m.isAnnotationPresent(Event.class))
					{
						if(m.getAnnotation(Event.class).type().equals(EventType.DISPATCHER))
						{
							//ONLY PROXY DISPATHERS
							return this.generateProxy(bean);
						}
					}
				}
			}
		}
		return bean;
	}
	
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException
	{
		for(String name : managedBeanNames)
		{
			if(beanName.equals(name))
			{
				for(Method m : bean.getClass().getMethods())
				{
					if(m.isAnnotationPresent(Event.class))
					{
						Event event = m.getAnnotation(Event.class);
						if(event.type().equals(EventType.LISTENER))
						{
							EventMapping.instance().addEventMapping(event.name(), bean);
						}
					}
				}
			}
		}
		
		return bean;
	}
	
	public void postProcessBeanFactory(
			ConfigurableListableBeanFactory beanFactory) throws BeansException
	{
		//NOOP
	}
	
	/**
	 * Create simple cglib proxy.
	 * 
	 * @param bean
	 * @return
	 */
	private Object generateProxy(Object bean)
	{
		return factory.generateProxy(bean);
	}
	
	public void setManagedBeanNames(List<String> managedBeanNames)
	{
		this.managedBeanNames = managedBeanNames;
	}
	
	public List<String> getManagedBeanNames()
	{
		return managedBeanNames;
	}
	
	public void setFactory(ObjectFactory factory)
	{
		this.factory = factory;
	}
	
	public ObjectFactory getFactory()
	{
		return factory;
	}
	
	private final static Logger log = Logger
			.getLogger(EventBeanPostProcessor.class);

}
